#define _GNU_SOURCE

#include "syscore.h"
#include <errno.h>
#include "syscore.x"
#include <signal.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#include <stdarg.h>
#include "../logServer/clogger.h"

typedef struct tagMODMSGSTATS {
    U32 numOK_Send;
    U32 numOK_Read;

    U32 numDiscarded_InactivePeer;
    U32 numDiscarded_TooLong;
    U32 numDiscarded_NoMem;
    U32 numDiscarded_QueueFull;
}MODMSGSTATS;

typedef struct tagSYSMSGSTATS {
    MODMSGSTATS modStats[MAX_MODULE_NUM];
    U32 numDiscarded_InvalidPeer;  // Just for reference. It's not thread safe thus not accurate. 
}SYSMSGSTATS;

SYSMSGSTATS sysMsgStats;

U32 sysTicks = 0;
U32 debuglevel = 5;

char *debugstr[DEBUG_MAX_LEVEL] ={
"EMERG",
"ALERT",
"CRIT",
"ERROR",
"WARNING",
"NOTICE",
"INFO",
"LOG_DEBUG"
} ;

U32 loglevel = 5;
char *logstr[LOG_MAX_LEVEL+1] ={
"EMERG",
"ALERT",
"CRIT",
"ERROR",
"WARNING",
"NOTICE",
"INFO",
"LOG_DEBUG"
} ;

extern U8 *msg_storage[MSG_BUFF_SIZE*4096];
extern MEMARRAY gMsgPart;
extern MODINFO gModInfo;
extern MQUEUE gModMQueue[MAX_MODULE_NUM];
extern SYSTIMER gSysTimer;
extern MODTIMER gModTimer[MAX_MODULE_NUM];
extern U32 sysTicks; 

static const U8 queueReadSeq[2][QUEUE_NUM_PER_MQ] = {{0,1,2},{0,2,1}};
static PMQUEUE MOD_getMQueue(U16 modID);
static void* MOD_popMessage(PMQUEUE pMQueue);

static TIMERCONTEXT* MOD_timerInit(U8 mIdx,U32 resolution);
static void MOD_timerDestroy(U8 mIdx);



RESULT SYS_initMemArray(PMEMARRAY pArray, void *storage, U32 blksz, U32 blkcnt)
{
	PTR *p;

	if ((((intptr_t)storage) & (sizeof(PTR)-1)) != 0)
    {   
        dbgprintf(DEBUG_ERROR,stderr,"storage not aligned, %p\n", storage );
        return RC_FAIL;
    }
	if (SYS_lock_init(&pArray->lock) != 0)
	{
	    dbgprintf(DEBUG_ERROR,stderr, __func__, __LINE__, LOG_ERR, "lock init error");
		return RC_FAIL;
	}

	blksz /= sizeof(PTR);

	pArray->storage = storage;
	pArray->blksz = blksz;
	pArray->blkcnt = blkcnt;
	pArray->end_of_storage = (PTR *)storage + blksz*blkcnt;
	
#ifdef MEMORY_MON
	pArray->refcount=0;
#endif
	// init storage
	pArray->freeblk = p = (PTR *)storage;
	while (blkcnt-- > 1)
	{
		*p = p + blksz;
		p = p + blksz;
	}
	*p = 0;
	
	return RC_OK;
}

RESULT SYS_destoryMemArray(PMEMARRAY pArray)
{
	SYS_lock_destory(&pArray->lock);
	return RC_OK;
}


void* SYS_allocMemArray(PMEMARRAY pArray )
{
    PTR *p;
    
    SYS_lock(&pArray->lock);
    
    p = pArray->freeblk;
    if (p == NULL)
    {
        SYS_unlock(&pArray->lock);
        return NULL;
    }
#ifndef NDEBUG 
    // FIXME: Remove after debugging
    if (( ((void*)p) < pArray->storage) || ( ((void*)p) >= pArray->end_of_storage))
    {

        dbgprintf(DEBUG_ERROR,stderr,
                "Corrupted MemArray;Arr=%p,Stor=%p,Free=%p\n",
                pArray, pArray->storage, pArray->freeblk);

        SYS_unlock(&pArray->lock);
        return NULL;
    }

    if ((*p != NULL) &&
        ((*p < pArray->storage) || (*p >= pArray->end_of_storage)))
    {
		dbgprintf(DEBUG_ERROR,stderr,
                "ERROR: Corrupted MemArray;Arr=%p,Stor=%p,Free=%p,Curr=%p\n",
                pArray, pArray->storage, pArray->freeblk,
                *pArray->freeblk);

        SYS_unlock(&pArray->lock);
        return NULL;
    }
#endif
    pArray->freeblk = *p;

	pArray->refcount++;
    SYS_unlock(&pArray->lock);

    return (void*)p;
}



RESULT SYS_freeMemArray(PMEMARRAY pArray, void *pBlock)
{
	if ((pBlock < pArray->storage) || (pBlock >= pArray->end_of_storage))
	{
		dbgprintf(DEBUG_ERROR,stderr,"Trying to free foreign block;Arr=%p,Blk=%p\n",
			   pArray, pBlock);

		return RC_FAIL;
	}

	SYS_lock(&pArray->lock);
	if (pArray->freeblk== pBlock)
	{
		// Simple protection against freeing of already freed block
		dbgprintf(DEBUG_WARNING,stderr,
					"Free already freed block %p\n", pBlock);
		SYS_unlock(&pArray->lock);
		return RC_OK;
	}

#ifndef NDEBUG
	if ((pArray->freeblk != NULL)
	    &&(( (void*)pArray->freeblk < pArray->storage)||( (void*)pArray->freeblk >= pArray->end_of_storage)))
	    
	{

		dbgprintf(DEBUG_ERROR,stderr,
				 "Corrupted MemArray;Arr=%p,Stor=%p,Free=%p\n",
				pArray, pArray->storage, pArray->freeblk);

		SYS_unlock(&pArray->lock);
		return RC_FAIL;
	}
#endif
	*((PTR *)pBlock) = pArray->freeblk;
	pArray->freeblk = pBlock;

	pArray->refcount--;

	SYS_unlock(&pArray->lock);
	return RC_OK;

}



RESULT SYS_initQueue(PQUEUE pQueue, void *storage,U32 size )
{
	pQueue->storage = storage;
	pQueue->get = 0;
	pQueue->put = 0;
	pQueue->size = size;
	SYS_lock_init(&pQueue->lock);

	return RC_OK;
}

RESULT SYS_destoryQueue(PQUEUE pQueue)
{
	SYS_lock_destory(&pQueue->lock);
	return RC_OK;
}

RESULT SYS_initMQueue(PMQUEUE pMQueue )
{
    U32 i = 0;
    SYS_sema_init(&pMQueue->sema);
    SYS_lock_init(&pMQueue->lock);
    pMQueue->queue_idx = 0;
    for (i = 0; i< QUEUE_NUM_PER_MQ;i++)
    {
        SYS_initQueue(&pMQueue->queue[i],pMQueue->storage+(i*QUEUE_SIZE),QUEUE_SIZE);
    }	

	return RC_OK;
}

RESULT SYS_destoryMQueue(PMQUEUE pMQueue )
{
    U32 i = 0;
    SYS_sema_destory(&pMQueue->sema);
    SYS_lock_destory(&pMQueue->lock);
    for (i = 0; i< QUEUE_NUM_PER_MQ;i++)
    {
        SYS_destoryQueue(&pMQueue->queue[i]);
    }	

	return RC_OK;
}


RESULT SYS_enqueue(PQUEUE pQueue, void* p)
{
	U32 put;
    U32 rc = RC_FAIL;
	
    SYS_lock(&pQueue->lock);
    put = pQueue->put;

    if (++put >= pQueue->size)
    {
        put = 0;
    }

    if (put != pQueue->get)
    {
        rc = RC_OK;
        pQueue->storage[pQueue->put] = p;
        pQueue->put = put;
    }
    SYS_unlock(&pQueue->lock);

    return rc;

}


void* SYS_dequeue(PQUEUE pQueue)
{
    U32 getIdx;
    void* p = NULL;

    SYS_lock(&pQueue->lock);
    getIdx = pQueue->get;
    
    if (pQueue->put != getIdx)
    {
        p = pQueue->storage[getIdx++];

        if (getIdx == pQueue->size)
        {
            getIdx = 0;
        }
        pQueue->get = getIdx;
    }
   
    SYS_unlock(&pQueue->lock);
    return p;
}




#if 0
void SYS_timerKick()
{
    
	if(++TimerkickCount >= SYSTIMER_INT_RESOLUTION)
	{
		TimerkickCount = 0;
	    SYS_sema_post(&sysTimerSema);
	}

}

#endif

void* SYS_timerTask(void* h)
{
    #define MAX_TICK_CNT_VAL     35
    #define MIN_TICK_CNT_VAL     1
    struct timespec ts;
    U32 time_int;
    U32 i, cnt, oldTicks, newTicks;
    struct timespec tv1,tv2;
    S16 ret;
    struct timespec tsN;
    static U32 err_in_nsec;
    
    pthread_setname_np(pthread_self(), "timer");

    ts.tv_sec = 0;
    ts.tv_nsec = SYSTIMER_RESOLUTION_NS;
    tsN.tv_sec = 0;
    tsN.tv_nsec = 0;

    err_in_nsec =  0;
    
    if (clock_gettime(CLOCK_MONOTONIC,&tv1) == -1)
    {
        dbgprintf(DEBUG_ERROR,stderr,"Error in gettime\n",NULL)
    }

       /* infinite loop */
    for (; ;)
    {
        ts.tv_nsec = SYSTIMER_RESOLUTION_NS - err_in_nsec;
        while ((ret = nanosleep (&ts, &tsN) != RC_OK) && (errno == EINTR))
        {
            ts.tv_nsec = tsN.tv_nsec;
            tsN.tv_nsec = 0;
            continue;
        }

        clock_gettime(CLOCK_MONOTONIC,&tv2);

        if ((tv2.tv_sec == tv1.tv_sec)&&(tv2.tv_nsec > tv1.tv_nsec))
        {
            time_int = (tv2.tv_nsec - tv1.tv_nsec);
        }
        else if (tv2.tv_sec > tv1.tv_sec)
        {
            time_int = ((tv2.tv_sec - tv1.tv_sec)*1000000000) + (tv2.tv_nsec - tv1.tv_nsec);
        }
        else /*  ts2 < ts1, this will not happen in normal scenario */
        {
            /* to make sure cnt = 1  */
            err_in_nsec = 0;
            time_int = SYSTIMER_RESOLUTION_NS;
        }

        oldTicks = sysTicks;
        sysTicks += (time_int/(SYSTIMER_RESOLUTION_NS - err_in_nsec));
        err_in_nsec = (time_int % (SYSTIMER_RESOLUTION_NS - err_in_nsec));
        newTicks = sysTicks;
        tv1.tv_nsec = tv2.tv_nsec;
        tv1.tv_sec = tv2.tv_sec;

        cnt = newTicks - oldTicks;

        while(err_in_nsec >= SYSTIMER_RESOLUTION_NS)
        {
            cnt++;
            err_in_nsec -= SYSTIMER_RESOLUTION_NS;
        }

        if( cnt >= MAX_TICK_CNT_VAL)
        {
            cnt = MIN_TICK_CNT_VAL;
            dbgprintf(DEBUG_ERROR,stderr,"Error in tick interval is too big\n",NULL);
        }
        /* call the common timer tick handler */
        for (i = 0; i < cnt; i++)
        {
            if(SYS_lock(&gSysTimer.context.lock) != RC_OK)
            {
                dbgprintf(DEBUG_ERROR,stderr,"Could not lock timer table\n",NULL);
                //continue;
            }
            TIMERS_proc(&gSysTimer.context);
            SYS_unlock(&gSysTimer.context.lock);

        }
    } 

}

RESULT SYS_timerInit()
{
    pthread_attr_t attr;
    pthread_t pthrd;
    struct sched_param  param;

    //SYS_sema_init(&sysTimerSema);
    if(SYS_initMemArray(&gSysTimer.timerPart,gSysTimer.storage,sizeof(TIMERINFO),NUM_SYS_TIMERS)  != RC_OK)
        return RC_FAIL;
    
    if(TIMERS_init(&gSysTimer.context,&gSysTimer.timerPart,SYSTIMER_RESOLUTION_MS) != RC_OK)
        return RC_FAIL;

    pthread_attr_init(&attr);
    
    pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
    pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
    param.sched_priority = sched_get_priority_max(SCHED_FIFO);;
    pthread_attr_setschedparam(&attr, &param);
    
    
    if( pthread_create(&pthrd, &attr, SYS_timerTask, NULL) != RC_OK)
    {
        dbgprintf(DEBUG_ERROR,stderr,"Create realtime thread failed, Are you root?\n",NULL);
        pthread_attr_destroy(&attr);
        return RC_FAIL; 
    }

    pthread_attr_destroy(&attr);
    return RC_OK;
    
}


void* MSG_alloc(void)
{
 
    return SYS_allocMemArray(&gMsgPart);
     
}

void MSG_free(void* pMsgDesc)
{
	SYS_freeMemArray(&gMsgPart,pMsgDesc);	
}



RESULT MSG_send(U16 peerID, MSGHEADER* pMsgHeader, void* pMsgPayload)
{
    PMSGHEADER pMyMsgHeader = NULL;
    PMQUEUE pMQueue = NULL;
    PQUEUE pQueue = NULL;
    
    if((pMQueue = MOD_getMQueue(peerID)) == NULL)
    {
        if((peerID < MODULE_ID_BASE) || (peerID >= (MODULE_ID_BASE + MAX_MODULE_NUM)))
        {
            sysMsgStats.numDiscarded_InvalidPeer++;
            
        }
        else
        {
            sysMsgStats.modStats[peerID-MODULE_ID_BASE].numDiscarded_InactivePeer++;
        }
        
        dbgprintf(DEBUG_ERROR,stdout,"Send message: Invalid peer. peer=%x,dstID=%x,srcID=%x,len=%x,type=%x\n",peerID, pMsgHeader->dstID,pMsgHeader->srcID,pMsgHeader->msgLength,pMsgHeader->msgType);
        return RC_MSG_DST_INVALID;
    }
    
    if( pMsgHeader->msgLength > MSG_BUFF_SIZE )
    {
        sysMsgStats.modStats[peerID-MODULE_ID_BASE].numDiscarded_TooLong++;
        
        dbgprintf(DEBUG_ERROR,stdout,"Send message: Too long. peer=%x,dstID=%x,srcID=%x,len=%x,type=%x\n",peerID, pMsgHeader->dstID,pMsgHeader->srcID,pMsgHeader->msgLength,pMsgHeader->msgType);
        return RC_MSG_TOO_LONG;
    }
    
    switch (pMsgHeader->msgType)
    {
        case MSG_TYPE_COMMAND:
            pQueue = &pMQueue->queue[2];
            break;
        case MSG_TYPE_INTERNAL:
            pQueue = &pMQueue->queue[1];
            break;
        case MSG_TYPE_TICK:
            pQueue = &pMQueue->queue[0];
            break;
        default:
            return RC_MSG_INVALID_VALUE;
            break;
    }

    pMyMsgHeader = MSG_alloc();
    if(NULL == pMyMsgHeader)
    {
        sysMsgStats.modStats[peerID-MODULE_ID_BASE].numDiscarded_NoMem++;
        dbgprintf(DEBUG_ERROR,stdout,"Send message: No memory. peer=%x,dstID=%x,srcID=%x,len=%x,type=%x\n",peerID, pMsgHeader->dstID,pMsgHeader->srcID,pMsgHeader->msgLength,pMsgHeader->msgType);
        return RC_MSG_NO_BUFF;  
    }
    
    memcpy((void*)pMyMsgHeader, (const void*)pMsgHeader, sizeof(MSGHEADER));
    
    if(pMsgPayload && pMsgHeader->msgLength)
    {          
        memcpy(pMyMsgHeader + 1, pMsgPayload, pMsgHeader->msgLength - sizeof(MSGHEADER));
    }

    if(RC_OK != SYS_enqueue(pQueue,pMyMsgHeader))
    {
       
            MSG_free(pMyMsgHeader);
            sysMsgStats.modStats[peerID-MODULE_ID_BASE].numDiscarded_QueueFull++;
            dbgprintf(DEBUG_ERROR,stdout,"Send message: Full Queue. peer=%x,dstID=%x,srcID=%x,len=%x,type=%x\n",peerID, pMsgHeader->dstID,pMsgHeader->srcID,pMsgHeader->msgLength,pMsgHeader->msgType);
            return RC_MSG_QUEUE_FULL;
        
    }
    SYS_sema_post(&pMQueue->sema);
    sysMsgStats.modStats[peerID-MODULE_ID_BASE].numOK_Send++;
    if(pMsgHeader->msgType != MSG_TYPE_TICK)
    dbgprintf(DEBUG_ALWAYS,stdout,"Send message: peer=%x,dstID=%x,srcID=%x,len=%x,type=%x\n",peerID, pMsgHeader->dstID,pMsgHeader->srcID,pMsgHeader->msgLength,pMsgHeader->msgType);
    return RC_OK;       
}



/*
 msg_read(PQUEUE pQueue,void* buff)

 Please make sure size of buff must >=MAX_MSG_SIZE;

*/
RESULT MSG_read(U16 selfID, MSGHEADER* pMsgHeader, void* pMsgPayload)
{
    PMSGHEADER pMyMsgHeader = NULL;
    PMQUEUE pMQueue = NULL;
    pMQueue = MOD_getMQueue(selfID);
    if(pMQueue == NULL)
        return RC_FAIL;
    
    while(TRUE)
    {
        SYS_sema_wait(&pMQueue->sema);
        pMyMsgHeader = MOD_popMessage(pMQueue);
        if( pMyMsgHeader != NULL )
        {
            if( pMyMsgHeader->msgLength <= MAX_MSG_SIZE)
                break;
            
            dbgprintf(DEBUG_ERROR,stderr,"Message is corrupted\n",NULL);
            MSG_free(pMyMsgHeader);  
            pMyMsgHeader = NULL;
        }
    }
    
    memcpy(pMsgHeader, pMyMsgHeader, sizeof(MSGHEADER));
    if(pMsgPayload &&pMyMsgHeader->msgLength )
    {
        memcpy(pMsgPayload, pMyMsgHeader + 1, pMyMsgHeader->msgLength - sizeof(MSGHEADER));
    }
    MSG_free(pMyMsgHeader);
    sysMsgStats.modStats[selfID-MODULE_ID_BASE].numOK_Read++;
    if(pMsgHeader->msgType != MSG_TYPE_TICK)
    dbgprintf(DEBUG_ALWAYS,stdout,"Recv message: dstID=%x,srcID=%x,len=%x,type=%x\n",pMsgHeader->dstID,pMsgHeader->srcID,pMsgHeader->msgLength,pMsgHeader->msgType);
    return RC_OK;
}

RESULT MSG_read_nonblock(U16 selfID,MSGHEADER* pMsgHeader, void* pMsgPayload)
{
    PMSGHEADER pMyMsgHeader = NULL;
    PMQUEUE pMQueue =NULL;
    
    pMQueue = MOD_getMQueue(selfID);
    if(pMQueue == NULL)
        return RC_FAIL;

    pMyMsgHeader = MOD_popMessage(pMQueue);
    if( pMyMsgHeader != NULL )
    {
        if( pMyMsgHeader->msgLength > MAX_MSG_SIZE)
        {
            dbgprintf(DEBUG_ERROR,stderr,"Message is corrupted\n", NULL);
            MSG_free(pMyMsgHeader);  
            pMyMsgHeader = NULL;
        }
    }


    if(pMyMsgHeader) 
    {
        memcpy(pMsgHeader, pMyMsgHeader, sizeof(MSGHEADER));
        if(pMsgPayload &&pMyMsgHeader->msgLength )
        {
            memcpy(pMsgPayload, pMyMsgHeader + 1, pMyMsgHeader->msgLength - sizeof(MSGHEADER));
        }
        MSG_free(pMyMsgHeader);
        sysMsgStats.modStats[selfID-MODULE_ID_BASE].numOK_Read++;
        if(pMsgHeader->msgType != MSG_TYPE_TICK)
        dbgprintf(DEBUG_ALWAYS,stdout,"Recv message: dstID=%x,srcID=%x,len=%x,type=%x\n",pMsgHeader->dstID,pMsgHeader->srcID,pMsgHeader->msgLength,pMsgHeader->msgType);
        return RC_OK;
    }
    else
    {
        return RC_NULL_RESULT;   
    }
}




MODDESC* MOD_getModDescriptor(U16 modID)
{ 
    if((modID < MODULE_ID_BASE) || (modID >= (MODULE_ID_BASE + MAX_MODULE_NUM)))
            return NULL;

    return &gModInfo.mod[modID - MODULE_ID_BASE];

}

PMQUEUE MOD_getMQueue(U16 modID)
{
    U16 mIdx;

    if( (modID < MODULE_ID_BASE) || (modID >= (MODULE_ID_BASE + MAX_MODULE_NUM)) )
    {
        dbgprintf(DEBUG_ERROR, stdout, "Invaild module id: 0x%04X\n", modID);
        return NULL;
    }

    mIdx = modID - MODULE_ID_BASE;
    if( gModInfo.mod[mIdx].valid )
        return gModInfo.mod[mIdx].pMQueue;
    else
    {
        dbgprintf(DEBUG_ERROR, stdout, "Module (0x%04X) is invaild \n", modID);
        return NULL;
    }
}

void* MOD_popMessage(PMQUEUE pMQueue)
{
    void* pMsg = NULL;
    int i =0;
        
    for(i=0; i < QUEUE_NUM_PER_MQ; i++)
    {
        pMsg = SYS_dequeue(&pMQueue->queue[queueReadSeq[pMQueue->queue_idx][i]]);
        if( pMsg != NULL )
        {
            break;        
        }

    }
    
    SYS_lock(&pMQueue->lock);
    //increase every time;
    pMQueue->queue_idx = (pMQueue->queue_idx + 1)%2;     
    SYS_unlock(&pMQueue->lock);

    return pMsg;

}


void MOD_tick(void *param)
{   
    MSGHEADER Headr;
    PMODDESC pModDesc = (PMODDESC) param;
    Headr.dstID = pModDesc->mod_id;
    Headr.srcID = MODULE_SYSTEM;
    Headr.msgType = MSG_TYPE_TICK;
    Headr.msgLength = 0;
    MSG_send(pModDesc->mod_id,&Headr,NULL);
    
    TIMERS_restart_timer(pModDesc->pTicker,pModDesc->tickPeriod);
}


RESULT MOD_register(PMODREG pModReg)
{   
    U16 modID = pModReg->modID;
    PMODINFO pModInfo = &gModInfo ;
    PMODDESC  pModDesc= NULL;
    
    U16 mIdx = 0;
    if((modID < MODULE_ID_BASE) || (modID >= (MODULE_ID_BASE + MAX_MODULE_NUM)))
        return RC_MOD_INVALID;

    mIdx = modID - MODULE_ID_BASE;

    if(pModReg->needTick)
    {
        if((pModReg->tickPeriod)&&(pModReg->tickPeriod%SYSTIMER_RESOLUTION_MS != 0))
            return RC_MSG_INVALID_VALUE;
    }

    pModDesc = &gModInfo.mod[mIdx];

    if(pModReg->logIdent )
    {
        if(strlen(pModReg->logIdent) > MAX_LOGIDENT_LEN)
            return RC_FAIL;        
    }
    
    if(pModDesc->valid)
        return RC_OK;
        
    if(SYS_initMQueue(&gModMQueue[mIdx]))
        return RC_FAIL;

    if(pModReg->logIdent)
    {
        strcpy(pModDesc->logIdent, pModReg->logIdent);
    }
    else
    {
        sprintf(pModDesc->logIdent,"%x",modID );
    }

    pModDesc->pMQueue = &gModMQueue[mIdx];
    pModDesc->mod_id= modID ;       
    pModInfo->mod_num++;
    pModInfo->reg_mask |= (0x01 <<mIdx);

    pModDesc->valid = TRUE; 
    
    pModDesc->pTicker = NULL;
    pModDesc->pTimerContext = NULL;

    
    if(pModReg->needTick)
    {
        pModDesc->tickPeriod = pModReg->tickPeriod;
        SYS_lock(&gSysTimer.context.lock);
        pModDesc->pTicker= TIMERS_start_timer(&gSysTimer.context,pModDesc->tickPeriod,MOD_tick,(void *)pModDesc);
        SYS_unlock(&gSysTimer.context.lock);

        if(pModReg->needModTimer)
        {
            pModDesc->pTimerContext = MOD_timerInit(mIdx,pModReg->tickPeriod);
        }
         
    }
    
    return RC_OK;
}



RESULT MOD_deregister(U16 modID)
{
    
    PMODINFO pModInfo = &gModInfo ;
    PMODDESC  pModDesc= NULL;
    U16 mIdx = 0;
    
    if((modID < MODULE_ID_BASE) || (modID >= (MODULE_ID_BASE + MAX_MODULE_NUM)))
        return RC_MOD_INVALID;
    
    mIdx = modID - MODULE_ID_BASE;  

    pModDesc = &gModInfo.mod[mIdx];

    if(pModDesc->valid == FALSE)
        return RC_OK;
    
    pModDesc->valid = FALSE;    
    SYS_destoryMQueue(pModDesc->pMQueue);    
    pModDesc->pMQueue = NULL;    

    if(pModDesc->pTicker)
    {
        SYS_lock(&gSysTimer.context.lock);
        TIMERS_clear_timer(&gSysTimer.context,pModDesc->pTicker);
        SYS_unlock(&gSysTimer.context.lock);
        pModDesc->pTicker= NULL;

    }

    if(pModDesc->pTimerContext)
    {
        MOD_timerDestroy(mIdx);
        pModDesc->pTimerContext = NULL;
    }

       
    pModInfo->mod_num--;
    pModInfo->reg_mask &= ~(0x01 <<mIdx);
    
    return RC_OK;
        
}



TIMERCONTEXT* MOD_timerInit(U8 mIdx,U32 resolution)
{
    
    SYS_initMemArray(&gModTimer[mIdx].timerPart,gModTimer[mIdx].storage,sizeof(TIMERINFO),NUM_MOD_TIMERS);
    TIMERS_init(&gModTimer[mIdx].context,&gModTimer[mIdx].timerPart,resolution);
    
    return &gModTimer[mIdx].context;


}

void MOD_timerDestroy(U8 mIdx)
{

    TIMERS_destory(&gModTimer[mIdx].context);
    SYS_destoryMemArray(&gModTimer[mIdx].timerPart);

}

void* MOD_timerStart(U16 modID, U32 msTime, CALLBACK cb, void *Param)
{
    PTIMERCONTEXT pTimerContext;
    PMODDESC pModDesc = MOD_getModDescriptor(modID);

    if( pModDesc && (pModDesc->valid))
    {

        pTimerContext = pModDesc->pTimerContext;

        if(pTimerContext == NULL) 
            return NULL;

        return (void*)TIMERS_start_timer(pTimerContext, msTime,cb,Param);

    }

    return NULL;
}

RESULT MOD_timerClear(U16 modID, void* pTimerInfo)
{
    PTIMERCONTEXT pTimerContext;
    PMODDESC pModDesc = MOD_getModDescriptor(modID);       
    
    if( pModDesc && (pModDesc->valid))
    {
    
        pTimerContext = pModDesc->pTimerContext;

        if(pTimerContext == NULL) 
            return RC_FAIL;

        TIMERS_clear_timer( pTimerContext,(PTIMERINFO)pTimerInfo);
         return RC_OK;
    }

    return RC_MOD_INVALID;
}

void MOD_timerRestart(void* pTimerInfo, U32 msTime)
{

    TIMERS_restart_timer((PTIMERINFO) pTimerInfo, msTime);
}



void MOD_timerProc(U16 modID )
{
    PMODDESC pModDesc = MOD_getModDescriptor(modID);

    if( pModDesc && (pModDesc->valid))
    {   
        PTIMERCONTEXT pTimerContext = pModDesc->pTimerContext;
        if(pTimerContext)
        {  
            //SYS_lock(&pTimerContext->lock);
            TIMERS_proc(pTimerContext);
            //SYS_unlock(&pTimerContext->lock);

        }
    }

}

void MOD_timerProc_lock(U16 modID )
{
    PMODDESC pModDesc = MOD_getModDescriptor(modID);

    if( pModDesc && (pModDesc->valid))
    {   
        PTIMERCONTEXT pTimerContext = pModDesc->pTimerContext;
        if(pTimerContext)
        {  
            SYS_lock(&pTimerContext->lock);
            TIMERS_proc(pTimerContext);
            SYS_unlock(&pTimerContext->lock);
        }
    }

}

RESULT SYS_init(void)
{
    
    // zero all global varible;
    memset(msg_storage,0,MSG_BUFF_SIZE*4096 );
    memset(&gMsgPart,0,sizeof(MEMARRAY));
    memset(&gModInfo,0,sizeof(MODINFO));
    memset(&gModMQueue,0,sizeof(MQUEUE)*MAX_MODULE_NUM );
    memset(&gSysTimer,0,sizeof(SYSTIMER));
    memset(&gModTimer,0,sizeof(MODTIMER)*MAX_MODULE_NUM);

    memset(&sysMsgStats,0,sizeof(SYSMSGSTATS));

    openlog("x86proj",LOG_CONS,LOG_USER);
        
    if(SYS_initMemArray(&gMsgPart,msg_storage,MSG_BUFF_SIZE,4096) != RC_OK)
        return RC_FAIL;
        
    if(SYS_timerInit() != RC_OK)
        return RC_FAIL;

    return RC_OK;

}

void MSG_printStats(void)
{
    int i = 0;
    MODDESC *pModDesc = NULL;
        
    dbgprintf_s(DEBUG_INFO, stdout, "****************   MODID[0x%x] System Message statistics (dec)************\n", MODULE_SYSTEM);
    dbgprintf_s(DEBUG_INFO, stdout, "modId[0x%x] numDiscarded_InvalidPeer : %x \n",sysMsgStats.numDiscarded_InvalidPeer, MODULE_SYSTEM);
    dbgprintf_s(DEBUG_INFO, stdout, "modId[0x%x]  ID     Send     Read InactivePeer  TooLong    NoMem QueueFull\n", MODULE_SYSTEM);
    
    for(i = 0; i< MAX_MODULE_NUM; i++)
    {
        pModDesc = &gModInfo.mod[i];
        if(pModDesc->valid)
        {
            dbgprintf_s(DEBUG_INFO, stdout, "%4x %8u %8u     %8u %8u %8u  %8u\n",
                i+MODULE_ID_BASE,
                sysMsgStats.modStats[i].numOK_Send,
                sysMsgStats.modStats[i].numOK_Read,
                sysMsgStats.modStats[i].numDiscarded_InactivePeer,
                sysMsgStats.modStats[i].numDiscarded_TooLong,
                sysMsgStats.modStats[i].numDiscarded_NoMem,
                sysMsgStats.modStats[i].numDiscarded_QueueFull
                );
        }
    }
}

void MOD_log(U16 modID,int priority, const char* fmt, ... )
{
    // MODDESC *pModDesc = MOD_getModDescriptor(modID);
    char fmtbuf[512];
    va_list args;

    if( priority > loglevel )
        return;

    //sprintf(fmtbuf,"[%s] [%s] %s",pModDesc->logIdent,logstr[priority],fmt);
    sprintf(fmtbuf, "[%04X] [%s] %s", modID, logstr[priority], fmt);
    va_start(args,fmt);
    vsyslog(priority,fmtbuf,args);
    va_end(args);

}

void SYS_log(int priority, const char* fmt, ... )
{
    char fmtbuf[512];
    va_list args;

    if(priority > loglevel)
        return;

    sprintf(fmtbuf,"[SYSCORE] [%s] %s",logstr[priority],fmt);
    va_start(args,fmt);
    vsyslog(priority,fmtbuf,args);
    va_end(args);

}

RESULT SYS_setLogLevel(U32 level)
{
    if(level <= LOG_MAX_LEVEL)
    {
        loglevel = level;
        return RC_OK;
    }
    else
    {
        return RC_FAIL;
    }
}

RESULT SYS_setDebugLevel(U32 level)
{
    if(level <= DEBUG_MAX_LEVEL)
    {
        debuglevel = level;
        return RC_OK;
    }
    else
    {
        return RC_FAIL;
    }
}

